package core.engine;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.nio.file.FileVisitResult;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;

import org.mapdb.DB;
import org.mapdb.DBMaker;
import org.mapdb.Serializer;

import core.exceptions.DBEngineException;
import session.Session;
import storage.io.FileManager;
import static storage.io.FileManager.DB_ROOT;
import storage.manager.DatabaseManager;

public class systemDBEngine {

    // 缓存系统数据库连接
    private static DB cachedSystemDB = null;
    private static final Object systemDBLock = new Object();
    private static boolean verboseLogging = false; // 控制是否输出详细日志

    /**
     * 设置是否输出详细日志
     * @param verbose 设置为true输出详细日志，false则只输出关键日志
     */
    public static void setVerboseLogging(boolean verbose) {
        verboseLogging = verbose;
    }

    /**
     * 初始化系统
     * 如果不提供数据库实例，方法会自动获取系统数据库并执行初始化
     * 如果提供数据库实例，方法会直接使用该实例执行初始化
     *
     * @param sysDB 可选的系统数据库实例参数
     */
    public static synchronized void initSystemTables(DB... sysDB) {
        // 如果未提供数据库实例，则自动获取
        if (sysDB.length == 0 || sysDB[0] == null) {
            try {
                DB newSysDB = getSystemDB();
                initSystemTablesInternal(newSysDB);
                // 注意：不在此处关闭数据库，因为它是缓存的
            } catch (Exception e) {
                System.err.println("初始化系统表失败: " + e.getMessage());
                throw new DBEngineException("初始化系统表失败: " + e.getMessage());
            }
        } else {
            // 使用提供的数据库实例
            initSystemTablesInternal(sysDB[0]);
        }
    }

    // 内部方法，执行实际的初始化操作
    @SuppressWarnings("unchecked")
    private static void initSystemTablesInternal(DB sysDB) {
        // 调用UserManager初始化用户表和权限
        security.auth.UserManager.initUserTable(sysDB);

        // 初始化数据库表（使用类型安全声明）
        ConcurrentMap<String, String> databases = sysDB
            .hashMap("databases", Serializer.STRING, Serializer.STRING)
            .createOrOpen();
        // 添加系统数据库
        databases.put("system_db", "system_database");

        // 初始化用户-数据库映射表 - 统一使用 Set<String>
        @SuppressWarnings("unchecked")
        ConcurrentMap<String, Set<String>> userDbMap = sysDB
            .hashMap("user_db_map", Serializer.STRING, Serializer.JAVA) // Serializer.JAVA 允许存储 Set
            .createOrOpen();
        // 添加系统预留映射，使用 HashSet
        if (!userDbMap.containsKey("system")) { // 确保只在第一次初始化时添加
            userDbMap.put("system", new HashSet<>()); 
        }

        // 初始化用户-授权数据库映射表 - 存储用户被授权访问的其他用户的数据库
        @SuppressWarnings("unchecked")
        ConcurrentMap<String, Map<String, Set<String>>> userAuthorizedDbMap = sysDB
            .hashMap("user_authorized_db_map", Serializer.STRING, Serializer.JAVA)
            .createOrOpen();
        // 添加系统预留映射
        if (!userAuthorizedDbMap.containsKey("system")) {
            userAuthorizedDbMap.put("system", new HashMap<>());
        }

        // 初始化数据库信息表
        ConcurrentMap<String, Map<String, Object>> dbInfoMap = sysDB
            .hashMap("db_info_map", Serializer.STRING, Serializer.JAVA)
            .createOrOpen();
        // 添加系统信息预留
        dbInfoMap.put("system_info", new HashMap<>());

        System.out.println("✅ 系统数据库表结构已初始化");
    }

    static {
        FileManager.initDBRoot(); // 确保目录存在
    }

    /**
     * 获取数据库实例
     * @param dbName 数据库名称
     * @return 数据库实例
     */
    public static DB getDatabase(String dbName) {
        try {
            // 获取当前用户
            String currentUser = storage.manager.DatabaseManager.getCurrentUser();

            // 使用与DatabaseManager一致的路径格式
            String dbFilePath;
            if ("system_db".equals(dbName)) {
                dbFilePath = Paths.get(FileManager.DB_ROOT, dbName + ".db").toString();
            } else {
                dbFilePath = Paths.get(FileManager.DB_ROOT, "USER", currentUser, dbName, dbName + ".db").toString();
            }

            // 创建数据库实例
            return DBMaker.fileDB(dbFilePath)
                    .fileLockDisable() // 完全禁用文件锁
                    .closeOnJvmShutdown()
                    .make();
        } catch (Exception e) {
            System.err.println("❌ 获取数据库实例失败: " + e.getMessage());
            return null;
        }
    }

    /**
     * 获取表结构存储（类型安全配置）
     * 设计说明:
     * - 键序列化: STRING 确保表名类型安全
     * - 值序列化: JAVA 支持复杂对象存储
     */

    @SuppressWarnings("unchecked")
    public static ConcurrentMap<String, Object> getSchemaStorage(DB db, String tableName) {
        return (ConcurrentMap<String, Object>) db.hashMap("schema_" + tableName)
                .keySerializer(Serializer.STRING)
                .valueSerializer(Serializer.JAVA)
                .createOrOpen();
    }

    @SuppressWarnings("unchecked")
    public static ConcurrentMap<Long, Object> getDataStorage(DB db, String tableName) {
        return (ConcurrentMap<Long, Object>) db.hashMap("data_" + tableName)
                .keySerializer(Serializer.LONG)
                .valueSerializer(Serializer.JAVA)
                .createOrOpen();
    }


    // 添加初始化状态检查
    public static boolean checkSystemTablesInitialized() {
        if (!systemDBExists()) {
            System.out.println("[INIT] 系统数据库文件不存在，需要初始化");
            return false;
        }

        if (FileManager.isSystemLocked()) {
            System.out.println("[INIT] 系统锁定中，等待解锁后初始化");
            return false;
        }

        // 进一步检查用户表是否已初始化
        try (DB sysDB = getSystemDB()) {
            // 检查users表是否存在
            boolean hasUsersTable = sysDB.exists("users");
            if (!hasUsersTable) {
                System.out.println("[INIT] 系统数据库缺少用户表，需要初始化");
                return false;
            }

            // 检查admin用户是否存在
            ConcurrentMap<String, String> users = sysDB
                .hashMap("users", Serializer.STRING, Serializer.STRING)
                .createOrOpen();

            if (!users.containsKey("admin")) {
                System.out.println("[INIT] 管理员用户不存在，需要初始化");
                return false;
            }

            System.out.println("[INIT] 系统已正确初始化，无需重新初始化");
            return true;
        } catch (Exception e) {
            System.err.println("[INIT] 检查系统表时出错: " + e.getMessage());
            return false;
        }
    }

    /**
     * 重置系统数据库文件和相关的WAL日志文件
     * WAL(Write-Ahead Logging)文件说明:
     * - 功能: WAL是一种日志先行写入机制，用于保证数据库事务的ACID特性
     * - 工作原理: 在修改数据库之前，先将操作记录到日志文件中，即使系统崩溃，也能根据日志恢复数据
     * - 文件格式: 系统数据库名.db.wal (例如: system_db.db.wal)
     * - 性能优势: 批量提交和顺序写入提高IO效率
     * - 数据安全: 防止崩溃时数据丢失或损坏
     * 警告: 删除WAL文件会导致未提交事务丢失，应谨慎操作
     *
     * @return 重置是否成功
     */
    public static boolean resetSystemDB() {
        System.out.println("⚠️ 开始强制重置系统数据库...");

        try {
            // 1. 强制关闭所有数据库连接
            System.out.println("强制关闭所有数据库连接...");
            DatabaseManager.closeAllDatabases();
            closeSystemDB();

            // 2. 强制垃圾回收，释放资源
            System.gc();
            System.runFinalization();

            // 3. 强制删除所有用户数据库文件
            System.out.println("强制删除所有用户数据库文件...");
            Path userRootPath = Paths.get(FileManager.DB_ROOT, "USER").toAbsolutePath();
            if (Files.exists(userRootPath)) {
                // 使用Files.walkFileTree来强制删除所有文件，但保留USER根目录
                Files.walkFileTree(userRootPath, new SimpleFileVisitor<Path>() {
                    @Override
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                        try {
                            // 强制删除文件
                            Files.delete(file);
                            System.out.println("已删除文件: " + file);
                        } catch (IOException e) {
                            // 如果文件被占用，尝试使用备用方法
                            if (e.getMessage().contains("另一个程序正在使用此文件") ||
                                e.getMessage().contains("正在使用") ||
                                e.getMessage().contains("Access is denied")) {
                                System.out.println("文件被占用，使用备用方法删除: " + file);
                                file.toFile().deleteOnExit();
                            }
                        }
                        return FileVisitResult.CONTINUE;
                    }

                    @Override
                    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                        // 使用绝对路径比较，确保只保留根USER目录
                        if (!dir.toAbsolutePath().equals(userRootPath)) {
                            try {
                                Files.delete(dir);
                                System.out.println("已删除目录: " + dir);
                            } catch (IOException e) {
                                // 如果目录不为空，等待一段时间后重试
                                if (e.getMessage().contains("目录不为空")) {
                                    try {
                                        Thread.sleep(1000);
                                        Files.delete(dir);
                                    } catch (Exception ex) {
                                        System.err.println("无法删除目录: " + dir);
                                    }
                                }
                            }
                        }
                        return FileVisitResult.CONTINUE;
                    }
                });
            }

            // 4. 强制删除系统数据库文件
            System.out.println("强制删除系统数据库文件...");
            Path dbPath = Paths.get(FileManager.DB_ROOT, "system_db.db");
            Path walPath = Paths.get(FileManager.DB_ROOT, "system_db.db.wal");

            try {
                Files.deleteIfExists(dbPath);
                Files.deleteIfExists(walPath);
            } catch (IOException e) {
                System.out.println("系统数据库文件被占用，使用备用方法删除");
                dbPath.toFile().deleteOnExit();
                walPath.toFile().deleteOnExit();
            }

            // 5. 重新初始化系统
            System.out.println("重新初始化系统...");
            initSystemTables();

            System.out.println("✅ 系统重置完成");
            return true;

        } catch (Exception e) {
            System.err.println("❌ 系统重置过程中出现错误: " + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 获取系统数据库实例
     * 优化版：使用缓存避免频繁打开关闭数据库连接
     *
     * @return 系统数据库实例
     */
    public static DB getSystemDB() {
        // 如果缓存的连接有效，直接返回
        if (cachedSystemDB != null && !cachedSystemDB.isClosed()) {
            if (verboseLogging) {
                System.out.println("[DEBUG] 使用缓存的系统数据库连接");
            }
            return cachedSystemDB;
        }

        // 同步锁确保线程安全
        synchronized(systemDBLock) {
            // 双重检查，防止多线程问题
            if (cachedSystemDB != null && !cachedSystemDB.isClosed()) {
                return cachedSystemDB;
            }

            try {
                Path path = Paths.get(DB_ROOT, "system_db.db");
                if (verboseLogging) {
                    System.out.println("[DEBUG] 尝试打开系统数据库: " + path);
                }

                File systemDbFile = new File(path.toString());
                if (!systemDbFile.exists()) {
                    if (verboseLogging) {
                        System.out.println("[DEBUG] 系统数据库文件不存在，将创建新文件");
                    }
                } else {
                    if (verboseLogging) {
                        System.out.println("[DEBUG] 系统数据库文件已存在，大小: " + systemDbFile.length() + " 字节");
                    }
                }

                cachedSystemDB = DBMaker.fileDB(systemDbFile)
                        .fileLockDisable() // 禁用文件锁
                        .transactionEnable()
                        .closeOnJvmShutdown()
                        .fileMmapEnable()
                        .make();

                if (verboseLogging) {
                    System.out.println("[DEBUG] 系统数据库打开成功");
                }
                return cachedSystemDB;
            } catch (Exception e) {
                System.err.println("[ERROR] 打开系统数据库失败: " + e.getMessage());
                StringWriter sw = new StringWriter();
                e.printStackTrace(new PrintWriter(sw));
                System.err.println("堆栈跟踪:\n" + sw.toString().replace("\t", "    "));
                throw new DBEngineException("无法打开系统数据库: " + e.getMessage());
            }
        }
    }

    /**
     * 关闭系统数据库连接（如有需要）
     * 在系统关闭或需要重置数据库时调用
     */
    public static void closeSystemDBCache() {
        synchronized(systemDBLock) {
            if (cachedSystemDB != null && !cachedSystemDB.isClosed()) {
                try {
                    System.out.println("[INFO] 关闭缓存的系统数据库连接");
                    cachedSystemDB.commit(); // 提交未保存的更改
                    cachedSystemDB.close();
                    cachedSystemDB = null;
                } catch (Exception e) {
                    System.err.println("[ERROR] 关闭系统数据库连接失败: " + e.getMessage());
                }
            }
        }
    }

    // 替换原有的方法，使其使用缓存的连接
    public static void closeSystemDB() {
        System.out.println("尝试关闭所有系统数据库连接...");

        // 关闭缓存的连接
        closeSystemDBCache();

        // 强制垃圾回收
        System.out.println("强制执行垃圾回收...");
        System.gc();
        System.runFinalization();

        // 等待资源释放
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        System.out.println("系统数据库连接清理完成");
    }

    public static boolean systemDBExists() {
        return Files.exists(Paths.get(DB_ROOT, "system_db.db"));
    }

    /**
     * 在系统数据库中存储用户创建的数据库映射信息
     *
     * @param username 用户名
     * @param dbName   数据库名
     */
    public static void addUserDatabaseMapping(String username, String dbName) {
        DB sysDB = getSystemDB();  //change
        try {
            // 获取用户数据库映射表
            @SuppressWarnings("unchecked")
            ConcurrentMap<String, Set<String>> userDbMap = sysDB
                .hashMap("user_db_map", Serializer.STRING, Serializer.JAVA)
                .createOrOpen();

            // 获取当前用户的数据库集合
            Set<String> userDatabases = userDbMap.get(username);
            if (userDatabases == null) {
                userDatabases = new HashSet<>();
            }

            // 添加新数据库（如果不存在）
            if (!userDatabases.contains(dbName)) {
                userDatabases.add(dbName);
                userDbMap.put(username, userDatabases);

                // 存储数据库详细信息 - Pass username as creatorUsername
                storeDatabaseInfo(sysDB, username, dbName);

                sysDB.commit();
                System.out.println("✅ 已将数据库 [" + dbName + "] 映射到用户 [" + username + "]");
            }

        } catch (Exception e) {
            System.err.println("❌ 添加用户数据库映射失败: " + e.getMessage());
            throw new DBEngineException("添加用户数据库映射失败: " + e.getMessage());
        }
    }

    /**
     * 存储数据库的详细信息（物理路径和表信息）
     *
     * @param sysDB 系统数据库实例
     * @param creatorUsername 数据库的创建者/所有者
     * @param dbName 数据库名
     */
    private static void storeDatabaseInfo(DB sysDB, String creatorUsername, String dbName) {
        ConcurrentMap<String, Map<String, Object>> dbInfoMap = sysDB
                .hashMap("db_info_map", Serializer.STRING, Serializer.JAVA)
                .createOrOpen();

        String dbKey = "DB:" + creatorUsername + ":" + dbName;
        Map<String, Object> info = dbInfoMap.getOrDefault(dbKey, new HashMap<>());

        // 修正 physicalPath 的构造逻辑
        // 确保与 DatabaseManager.getPhysicalDbPath 一致
        // 路径应该是： DBMS_ROOT/USER/creatorUsername/dbName_folder/dbName.db
        String physicalStoragePath = Paths.get(FileManager.DB_ROOT, "USER", creatorUsername, dbName, dbName + FileManager.DB_EXTENSION).toString();

        info.put("physicalPath", physicalStoragePath);
        info.put("creator", creatorUsername);
        info.put("createTime", java.time.LocalDateTime.now().toString());

        // 初始化权限用户列表，仅包含创建者
        Set<String> permissionedUsers = new HashSet<>();
        permissionedUsers.add(creatorUsername);
        info.put("permissionedUsers", permissionedUsers);

        if (!info.containsKey("tables")) {
            info.put("tables", new ArrayList<String>()); // 初始化表列表
        }

        dbInfoMap.put(dbKey, info);
        if (verboseLogging) System.out.println("ℹ️ 数据库元数据已为 '" + dbKey + "' 存储/更新，路径: " + physicalStoragePath);
    }

    /**
     * 当数据库中添加了新表时，更新数据库信息
     *
     * @param ownerName 数据库所有者
     * @param dbName    数据库名
     * @param tableName 表名
     */
    public static void addTableToDatabase(String ownerName, String dbName, String tableName) {
        try (DB sysDB = getSystemDB()) {
            // 数据库信息映射表
            @SuppressWarnings("unchecked")
            ConcurrentMap<String, Map<String, Object>> dbInfoMap = sysDB
                .hashMap("db_info_map", Serializer.STRING, Serializer.JAVA)
                .createOrOpen();

            String dbKey = "DB:" + ownerName + ":" + dbName;

            // 获取数据库信息
            Map<String, Object> dbInfo = dbInfoMap.get(dbKey);
            if (dbInfo == null) {
                // This should ideally not happen if addTableToDatabase is called for an existing, owned DB.
                // If it can, creating a new dbInfo entry here might be incorrect as physical path etc. might be missing
                // or default-initialized incorrectly.
                System.err.println("❌ 更新表信息失败：数据库 " + ownerName + "." + dbName + " 的元数据不存在。");
                // For robustness, one might re-create a basic dbInfo if that's a valid scenario,
                // but it implies the DB wasn't properly registered before.
                // For now, let's throw an exception or return, as adding a table to non-existent DB metadata is an issue.
                throw new DBEngineException("无法向不存在元数据的数据库添加表: " + ownerName + "." + dbName);
            }

            // 获取表列表
            @SuppressWarnings("unchecked")
            List<String> tables = (List<String>) dbInfo.get("tables");
            if (tables == null) { // Should have been initialized as empty list
                tables = new ArrayList<>();
            }

            // 添加新表（如果不存在）
            if (!tables.contains(tableName)) {
                tables.add(tableName);
                dbInfo.put("tables", tables);
                dbInfoMap.put(dbKey, dbInfo);
                sysDB.commit();
                System.out.println("✅ 已将表 [" + tableName + "] 添加到数据库 [" + ownerName + "." + dbName + "] 信息中");
            }

        } catch (Exception e) {
            System.err.println("❌ 更新数据库表信息失败: " + e.getMessage());
            throw new DBEngineException("更新数据库表信息失败: " + e.getMessage());
        }
    }

    /**
     * 获取用户创建的所有数据库列表
     *
     * @param username 用户名
     * @return 数据库名称列表
     */
    public static List<String> getUserDatabases(String username) {
        DB sysDB = getSystemDB(); // 获取系统数据库实例 change
        try  {
            @SuppressWarnings("unchecked")
            ConcurrentMap<String, Set<String>> userDbMap = sysDB
                .hashMap("user_db_map", Serializer.STRING, Serializer.JAVA)
                .createOrOpen();

            // 获取用户的数据库集合
            Set<String> userDatabases = userDbMap.get(username);
            if (userDatabases == null) {
                return new ArrayList<>();
            }

            // 获取数据库信息映射表以验证数据库是否存在
            @SuppressWarnings("unchecked")
            ConcurrentMap<String, Map<String, Object>> dbInfoMap = sysDB
                .hashMap("db_info_map", Serializer.STRING, Serializer.JAVA)
                .createOrOpen();

            // 验证每个数据库是否存在，并使用新格式的键名
            List<String> validatedDatabases = new ArrayList<>();
            for (String dbName : userDatabases) {
                // 使用新格式检查数据库信息
                String dbKey = "DB:" + username + ":" + dbName;

                // 如果找到了数据库信息，添加到有效列表
                if (dbInfoMap.containsKey(dbKey)) {
                    validatedDatabases.add(dbName);
                    continue;
                }

                // 向后兼容：检查旧格式
                String oldFormatKey = username + "_" + dbName;
                if (dbInfoMap.containsKey(oldFormatKey)) {
                    // 迁移到新格式
                    Map<String, Object> dbInfo = dbInfoMap.get(oldFormatKey);
                    dbInfoMap.put(dbKey, dbInfo);
                    dbInfoMap.remove(oldFormatKey);
                    validatedDatabases.add(dbName);
                    sysDB.commit();
                    continue;
                }

                // 检查原始格式
                if (dbInfoMap.containsKey(dbName)) {
                    // 迁移到新格式
                    Map<String, Object> dbInfo = dbInfoMap.get(dbName);
                    dbInfoMap.put(dbKey, dbInfo);
                    dbInfoMap.remove(dbName);
                    validatedDatabases.add(dbName);
                    sysDB.commit();
                }
            }

            return validatedDatabases;
        } catch (Exception e) {
            System.err.println("❌ 获取用户数据库列表失败: " + e.getMessage());
            throw new DBEngineException("获取用户数据库列表失败: " + e.getMessage());
        }
    }

    /**
     * 获取数据库的详细信息
     *
     * @param ownerName 数据库的所有者 (例如 "user1", 或 "system" for system_db)
     * @param dbName 数据库名
     * @return 数据库信息Map，包含物理路径和表列表；如果未找到则返回null或空Map
     */
    public static Map<String, Object> getDatabaseInfo(String ownerName, String dbName) {
        if (ownerName == null || ownerName.trim().isEmpty() || dbName == null || dbName.trim().isEmpty()) {
            System.err.println("[ERROR] getDatabaseInfo: ownerName 和 dbName 不能为空。");
            return new HashMap<>(); // 或者抛出异常
        }

        String effectiveOwnerName = ownerName;
        // system_db is a special case, its owner is "system".
        if ("system_db".equals(dbName) && !"system".equals(ownerName)) {
            // If someone queries for system_db but specifies a wrong owner, clarify it's "system"
            // Or, strictly, if they asked for "user1.system_db", it shouldn't exist.
            // Let's assume if dbName is system_db, ownerName *must* be system for a valid lookup.
            // However, Session/DatabaseManager might default owner to "system" for system_db already.
            // For now, this method will trust the provided ownerName.
            // If ownerName is "user1" and dbName is "system_db", it will look for "DB:user1:system_db" which is likely not found.
        }

        DB sysDB = getSystemDB();
        try  {
            @SuppressWarnings("unchecked")
            ConcurrentMap<String, Map<String, Object>> dbInfoMap = sysDB
                .hashMap("db_info_map", Serializer.STRING, Serializer.JAVA)
                .createOrOpen();

            String dbKey = "DB:" + effectiveOwnerName + ":" + dbName;
            Map<String, Object> dbInfo = dbInfoMap.get(dbKey);

            // No fallback to old key formats as the new system relies on explicit owner.db
            // Migration of old keys should be a separate, one-time utility if needed.

            return dbInfo != null ? dbInfo : new HashMap<>(); // Return empty map if not found, consistent with old behavior
        } catch (Exception e) {
            System.err.println("❌ 获取数据库 [" + effectiveOwnerName + "." + dbName + "] 信息失败: " + e.getMessage());
            throw new DBEngineException("获取数据库信息失败: " + e.getMessage());
        }
    }

    /**
     * 获取所有数据库的信息 (db_info_map 的完整内容)
     * 主要由 DatabaseManager.showDatabases 使用。
     *
     * @return 包含所有数据库信息的Map，键为内部存储键 (DB:owner:dbName)，值为数据库属性Map。
     */
    public static Map<String, Map<String, Object>> getAllDatabaseInfo() {
        DB sysDB = getSystemDB();
        try {
            @SuppressWarnings("unchecked")
            ConcurrentMap<String, Map<String, Object>> dbInfoMap = sysDB
                .hashMap("db_info_map", Serializer.STRING, Serializer.JAVA)
                .createOrOpen();
            // Return a copy to prevent modification issues if the caller modifies the map
            // And to ensure it's a regular Map, not a ConcurrentMap, if that matters to caller.
            return new HashMap<>(dbInfoMap);
        } catch (Exception e) {
            System.err.println("❌ 获取所有数据库信息列表失败: " + e.getMessage());
            throw new DBEngineException("获取所有数据库信息列表失败: " + e.getMessage());
        }
    }

    public static void grantPrivilege(String ownerName, String dbName, String targetUser) throws DBEngineException {
        synchronized (systemDBLock) {
            try (DB sysDB = getSystemDB()) {
                ConcurrentMap<String, Map<String, Object>> dbInfoMap = sysDB
                        .hashMap("db_info_map", Serializer.STRING, Serializer.JAVA)
                        .createOrOpen();

                String dbKey = "DB:" + ownerName + ":" + dbName;

                // 校验数据库是否存在
                if (!dbInfoMap.containsKey(dbKey)) {
                    throw new DBEngineException("数据库 " + ownerName + "." + dbName + " 不存在。");
                }

                // 校验目标用户是否存在
                if (!security.auth.UserManager.userExists(targetUser)) {
                    throw new DBEngineException("用户 " + targetUser + " 不存在。");
                }

                String currentUser = Session.getCurrentUser();
                if (currentUser == null) {
                    throw new DBEngineException("无法确定当前用户，操作被拒绝。");
                }

                // 只有管理员或数据库所有者可以执行GRANT操作
                boolean isAdmin = security.auth.UserManager.isAdmin(currentUser);
                boolean isOwner = ownerName.equals(currentUser);
                if (!isAdmin && !isOwner) {
                    throw new DBEngineException("用户 " + currentUser + " 不是管理员或数据库所有者，无权执行GRANT操作。");
                }

                Map<String, Object> dbInfo = dbInfoMap.get(dbKey);
                if (dbInfo == null) { // 理论上如果containsKey为true，这里不应为null，但作为安全检查
                    throw new DBEngineException("无法获取数据库 " + ownerName + "." + dbName + " 的信息。");
                }

                @SuppressWarnings("unchecked")
                Set<String> permissionedUsers = (Set<String>) dbInfo.get("permissionedUsers");
                if (permissionedUsers == null) { // 防御性编程，理论上初始化时已创建
                    permissionedUsers = new HashSet<>();
                }

                String creator = (String) dbInfo.get("creator");

                // 检查用户是否已经是创建者
                if (targetUser.equals(creator)) {
                    System.out.println("用户 " + targetUser + " 是数据库 " + ownerName + "." + dbName + " 的创建者，无需重复授权。");
                    return; // 创建者默认拥有所有权限
                }

                // 检查用户是否已经拥有权限
                if (permissionedUsers.contains(targetUser)) {
                    System.out.println("用户 " + targetUser + " 已拥有数据库 " + ownerName + "." + dbName + " 的权限。");
                    return;
                }

                // 更新数据库信息表中的权限用户集合
                permissionedUsers.add(targetUser);
                dbInfo.put("permissionedUsers", permissionedUsers);
                dbInfoMap.put(dbKey, dbInfo); // 更新回MapDB

                // 更新用户授权数据库映射表
                @SuppressWarnings("unchecked")
                ConcurrentMap<String, Map<String, Set<String>>> userAuthorizedDbMap = sysDB
                        .hashMap("user_authorized_db_map", Serializer.STRING, Serializer.JAVA)
                        .createOrOpen();

                // 获取或创建目标用户的授权数据库映射
                Map<String, Set<String>> userAuthorizedDbs = userAuthorizedDbMap.get(targetUser);
                if (userAuthorizedDbs == null) {
                    userAuthorizedDbs = new HashMap<>();
                }

                // 获取或创建该拥有者对应的数据库集合
                Set<String> ownerDbs = userAuthorizedDbs.get(ownerName);
                if (ownerDbs == null) {
                    ownerDbs = new HashSet<>();
                }

                // 添加被授权的数据库
                ownerDbs.add(dbName);
                userAuthorizedDbs.put(ownerName, ownerDbs);
                userAuthorizedDbMap.put(targetUser, userAuthorizedDbs);

                sysDB.commit();
                System.out.println("✅ 权限已授予：用户 " + targetUser + " 现在可以访问数据库 " + ownerName + "." + dbName);

            } catch (DBEngineException e) {
                throw e; // 直接重新抛出我们自己的业务异常
            } catch (Exception e) {
                StringWriter sw = new StringWriter();
                e.printStackTrace(new PrintWriter(sw));
                String errorDetails = "授予权限时发生内部错误：" + e.getMessage() + "\nStack trace:\n" + sw.toString();
                System.err.println(errorDetails);
                throw new DBEngineException(errorDetails);
            }
        }
    }

    public static void revokePrivilege(String ownerName, String dbName, String targetUser) throws DBEngineException {
        synchronized (systemDBLock) {
            try (DB sysDB = getSystemDB()) {
                ConcurrentMap<String, Map<String, Object>> dbInfoMap = sysDB
                        .hashMap("db_info_map", Serializer.STRING, Serializer.JAVA)
                        .createOrOpen();

                String dbKey = "DB:" + ownerName + ":" + dbName;

                // 校验数据库是否存在
                if (!dbInfoMap.containsKey(dbKey)) {
                    throw new DBEngineException("数据库 " + ownerName + "." + dbName + " 不存在。");
                }

                // 校验目标用户是否存在
                if (!security.auth.UserManager.userExists(targetUser)) {
                    throw new DBEngineException("用户 " + targetUser + " 不存在。无法撤销不存在用户的权限。");
                }

                String currentUser = Session.getCurrentUser();
                if (currentUser == null) {
                    throw new DBEngineException("无法确定当前用户，操作被拒绝。");
                }

                // 只有管理员或数据库所有者可以执行REVOKE操作
                boolean isAdmin = security.auth.UserManager.isAdmin(currentUser);
                boolean isOwner = ownerName.equals(currentUser);
                if (!isAdmin && !isOwner) {
                    throw new DBEngineException("用户 " + currentUser + " 不是管理员或数据库所有者，无权执行REVOKE操作。");
                }

                Map<String, Object> dbInfo = dbInfoMap.get(dbKey);
                if (dbInfo == null) {
                    throw new DBEngineException("无法获取数据库 " + ownerName + "." + dbName + " 的信息。");
                }

                String creator = (String) dbInfo.get("creator");

                // 不能撤销数据库创建者自己的权限
                if (targetUser.equals(creator)) {
                    throw new DBEngineException("不能撤销数据库 " + ownerName + "." + dbName + " 创建者 (" + creator + ") 的权限。");
                }

                @SuppressWarnings("unchecked")
                Set<String> permissionedUsers = (Set<String>) dbInfo.get("permissionedUsers");

                if (permissionedUsers == null || !permissionedUsers.contains(targetUser)) {
                    // 如果用户本来就没有权限，或者权限集合为空，则认为操作已完成（或无需操作）
                    System.out.println("用户 " + targetUser + " 并未被授予数据库 " + ownerName + "." + dbName + " 的权限，无需撤销。");
                    return; // 无需操作或用户本就无权限
                }

                // 更新数据库信息表中的权限用户集合
                permissionedUsers.remove(targetUser);
                dbInfo.put("permissionedUsers", permissionedUsers);
                dbInfoMap.put(dbKey, dbInfo); // 更新回MapDB

                // 更新用户授权数据库映射表
                @SuppressWarnings("unchecked")
                ConcurrentMap<String, Map<String, Set<String>>> userAuthorizedDbMap = sysDB
                        .hashMap("user_authorized_db_map", Serializer.STRING, Serializer.JAVA)
                        .createOrOpen();

                // 获取目标用户的授权数据库映射
                Map<String, Set<String>> userAuthorizedDbs = userAuthorizedDbMap.get(targetUser);
                if (userAuthorizedDbs != null) {
                    // 获取该拥有者对应的数据库集合
                    Set<String> ownerDbs = userAuthorizedDbs.get(ownerName);
                    if (ownerDbs != null) {
                        // 移除被撤销的数据库
                        ownerDbs.remove(dbName);
                        
                        // 如果集合为空，则删除该拥有者的映射
                        if (ownerDbs.isEmpty()) {
                            userAuthorizedDbs.remove(ownerName);
                        } else {
                            userAuthorizedDbs.put(ownerName, ownerDbs);
                        }

                        // 如果该用户没有任何授权数据库，则删除整个映射
                        if (userAuthorizedDbs.isEmpty()) {
                            userAuthorizedDbMap.remove(targetUser);
                        } else {
                            userAuthorizedDbMap.put(targetUser, userAuthorizedDbs);
                        }
                    }
                }

                sysDB.commit();
                System.out.println("✅ 权限已撤销：用户 " + targetUser + " 现在无法访问数据库 " + ownerName + "." + dbName);

            } catch (DBEngineException e) {
                throw e; // 直接重新抛出我们自己的业务异常
            } catch (Exception e) {
                StringWriter sw = new StringWriter();
                e.printStackTrace(new PrintWriter(sw));
                String errorDetails = "撤销权限时发生内部错误：" + e.getMessage() + "\nStack trace:\n" + sw.toString();
                System.err.println(errorDetails);
                throw new DBEngineException(errorDetails);
            }
        }
    }

    /**
     * 删除数据库的元数据，包括 db_info_map 中的条目和 user_db_map 中的所有相关映射。
     * 执行此操作的用户必须是管理员，或者是指定数据库的创建者。
     *
     * @param ownerName 数据库的预期所有者/创建者
     * @param dbName    要删除元数据的数据库名
     * @return 如果成功删除，返回数据库的实际创建者用户名；如果权限不足或数据库未找到，则抛出DBEngineException
     * @throws DBEngineException 如果操作失败（例如，权限不足，数据库不存在等）
     */
    public static String deleteDatabaseMetadata(String ownerName, String dbName) throws DBEngineException {
        DB sysDB = getSystemDB();
        String currentUser = Session.getCurrentUser();
        if (currentUser == null) {
            throw new DBEngineException("删除数据库元数据失败：用户未登录。");
        }

        try {
            // 1. 处理 db_info_map
            @SuppressWarnings("unchecked")
            ConcurrentMap<String, Map<String, Object>> dbInfoMap = sysDB
                .hashMap("db_info_map", Serializer.STRING, Serializer.JAVA)
                .createOrOpen();

            String dbKeyToDelete = "DB:" + ownerName + ":" + dbName;
            Map<String, Object> dbInfo = dbInfoMap.get(dbKeyToDelete);

            if (dbInfo == null || dbInfo.isEmpty()) {
                throw new DBEngineException("删除数据库元数据失败：数据库 '" + ownerName + "." + dbName + "' 未找到。");
            }

            String actualCreator = (String) dbInfo.get("creator");
            if (actualCreator == null || !actualCreator.equals(ownerName)) {
                // 键中的ownerName和元数据中的creator不一致，这是一个严重问题，或者键构造逻辑有误
                throw new DBEngineException("删除数据库元数据失败：数据库键与元数据不匹配。预期创建者: " + ownerName + ", 实际: " + actualCreator);
            }

            boolean isAdmin = security.auth.UserManager.isAdmin(currentUser);
            // 权限检查: 执行者必须是管理员，或者是数据库的创建者 (actualCreator)
            if (!isAdmin && !currentUser.equals(actualCreator)) {
                throw new DBEngineException("删除数据库元数据失败：用户 [" + currentUser + "] 无权删除数据库 [" + ownerName + "." + dbName + "]。");
            }

            // 从 db_info_map 中删除 (实际删除推迟到commit前，或在事务中执行)
            // dbInfoMap.remove(dbKeyToDelete);
            // System.out.println("✅ 已从 db_info_map 中删除数据库 [" + ownerName + "." + dbName + "] 的元数据。"); // 日志移到commit后

            // 2. 处理 user_db_map：移除所有用户对此数据库的映射
            @SuppressWarnings("unchecked")
            ConcurrentMap<String, Set<String>> userDbMap = sysDB
                .hashMap("user_db_map", Serializer.STRING, Serializer.JAVA)
                .createOrOpen();

            boolean mappingChangedInUserDbMap = false;
            for (Map.Entry<String, Set<String>> entry : userDbMap.entrySet()) {
                String mappedUser = entry.getKey();
                Set<String> userDatabases = entry.getValue();

                // 防御 ClassCastException，尽管我们期望现在都是Set
                if (!(userDatabases instanceof Set)) {
                    System.err.println("警告: 用户 '" + mappedUser + "' 的数据库列表类型不是 Set，而是 " + (userDatabases == null ? "null" : userDatabases.getClass().getName()) + ". 跳过此条目以防止崩溃。");
                    continue;
                }

                if (userDatabases.remove(dbName)) { // 只比较 dbName，因为 user_db_map 中不含 owner
                    mappingChangedInUserDbMap = true;
                    if (userDatabases.isEmpty()) {
                        userDbMap.remove(mappedUser); // 如果用户没有其他数据库映射，则移除该用户条目
                    } else {
                        userDbMap.put(mappedUser, userDatabases); // 更新该用户的数据库列表
                    }
                    if (verboseLogging) System.out.println("ℹ️ 已准备从用户 [" + mappedUser + "] 的映射中移除数据库 [" + dbName + "]。");
                }
            }

            // 在提交前实际执行来自 db_info_map 的删除
            dbInfoMap.remove(dbKeyToDelete);

            sysDB.commit(); // 所有操作成功，提交事务

            // 提交成功后打印日志
            System.out.println("✅ 数据库 [" + ownerName + "." + dbName + "] 的元数据已成功从 db_info_map 中删除。");
            if (mappingChangedInUserDbMap) {
                System.out.println("✅ 数据库 [" + dbName + "] 的相关用户映射已成功更新/移除。");
            }

            return actualCreator; // 返回数据库的实际创建者

        } catch (Exception e) {
            try {
                sysDB.rollback();
                System.err.println("❌ 删除数据库元数据操作因错误已回滚: " + e.getMessage());
            } catch (Exception rbEx) {
                System.err.println("❌ 删除数据库元数据操作失败，且回滚也失败: " + rbEx.getMessage());
            }
            if (e instanceof DBEngineException) throw (DBEngineException) e;
            throw new DBEngineException("删除数据库元数据时出错: " + e.getMessage() + (e.getCause() != null ? " Cause: " + e.getCause().getMessage() : ""));
        }
    }

    /**
     * 获取用户被授权访问的其他用户的数据库
     *
     * @param username 用户名
     * @return Map<拥有者, Set<数据库名>> 形式的映射表
     * @throws DBEngineException 如果操作失败
     */
    public static Map<String, Set<String>> getUserAuthorizedDatabases(String username) throws DBEngineException {
        if (username == null || username.trim().isEmpty()) {
            throw new DBEngineException("用户名不能为空");
        }

        synchronized (systemDBLock) {
            try (DB sysDB = getSystemDB()) {
                @SuppressWarnings("unchecked")
                ConcurrentMap<String, Map<String, Set<String>>> userAuthorizedDbMap = sysDB
                        .hashMap("user_authorized_db_map", Serializer.STRING, Serializer.JAVA)
                        .createOrOpen();

                Map<String, Set<String>> userAuthorizedDbs = userAuthorizedDbMap.get(username);
                if (userAuthorizedDbs == null) {
                    return new HashMap<>(); // 返回空映射而不是null
                }

                // 创建一个深拷贝，以避免外部修改影响内部存储
                Map<String, Set<String>> result = new HashMap<>();
                for (Map.Entry<String, Set<String>> entry : userAuthorizedDbs.entrySet()) {
                    result.put(entry.getKey(), new HashSet<>(entry.getValue()));
                }
                return result;
            } catch (Exception e) {
                StringWriter sw = new StringWriter();
                e.printStackTrace(new PrintWriter(sw));
                String errorDetails = "获取用户授权数据库时发生内部错误: " + e.getMessage() + "\nStack trace:\n" + sw.toString();
                System.err.println(errorDetails);
                throw new DBEngineException(errorDetails);
            }
        }
    }

    /**
     * 直接获取指定数据库的所有表名
     * 此方法不依赖于当前会话的数据库，可用于访问权限检查后的表列表获取
     *
     * @param ownerName 数据库所有者
     * @param dbName 数据库名称
     * @return 表名列表
     */
    public static List<String> getTablesForDatabase(String ownerName, String dbName) {
        System.out.println("[systemDBEngine.getTablesForDatabase] 尝试获取数据库 " + ownerName + "." + dbName + " 的表列表");
        List<String> tables = new ArrayList<>();
        
        try {
            // 首先从数据库信息中获取
            Map<String, Object> dbInfo = getDatabaseInfo(ownerName, dbName);
            if (dbInfo != null && dbInfo.containsKey("tables")) {
                @SuppressWarnings("unchecked")
                List<String> dbTables = (List<String>) dbInfo.get("tables");
                if (dbTables != null && !dbTables.isEmpty()) {
                    tables.addAll(dbTables);
                    System.out.println("[systemDBEngine.getTablesForDatabase] 从数据库信息中获取到 " + tables.size() + " 个表");
                    return tables;
                }
            }
            
            // 如果从数据库信息中获取失败，尝试从系统表中获取
            try (DB sysDB = getSystemDB()) {
                if (sysDB == null) {
                    System.err.println("[systemDBEngine.getTablesForDatabase] 无法获取系统数据库连接");
                    return tables;
                }
                
                // 查询system_tables表
                @SuppressWarnings("unchecked")
                ConcurrentMap<String, Map<String, Object>> systemTables = sysDB
                        .hashMap("system_tables", Serializer.STRING, Serializer.JAVA)
                        .createOrOpen();
                
                // 遍历查找符合条件的表
                for (Map.Entry<String, Map<String, Object>> entry : systemTables.entrySet()) {
                    Map<String, Object> tableInfo = entry.getValue();
                    if (tableInfo != null && 
                        ownerName.equals(tableInfo.get("db_owner")) && 
                        dbName.equals(tableInfo.get("db_name"))) {
                        String tableName = String.valueOf(tableInfo.get("table_name"));
                        if (tableName != null && !tableName.isEmpty()) {
                            tables.add(tableName);
                        }
                    }
                }
                
                System.out.println("[systemDBEngine.getTablesForDatabase] 从系统表中获取到 " + tables.size() + " 个表");
            }
            
            // 如果表列表仍为空，尝试从文件系统获取
            if (tables.isEmpty()) {
                String dbPath;
                if ("system_db".equals(dbName) && "system".equals(ownerName)) {
                    dbPath = Paths.get(FileManager.DB_ROOT, dbName + ".db").toString();
                } else {
                    dbPath = Paths.get(FileManager.DB_ROOT, "USER", ownerName, dbName, dbName + ".db").toString();
                }
                
                File dbFile = new File(dbPath);
                if (dbFile.exists()) {
                    try (DB db = DBMaker.fileDB(dbFile)
                            .fileLockDisable()
                            .readOnly()
                            .closeOnJvmShutdown()
                            .make()) {
                        
                        for (String mapName : db.getAllNames()) {
                            if (mapName.startsWith("schema_")) {
                                String tableName = mapName.substring(7); // 去掉"schema_"前缀
                                tables.add(tableName);
                            }
                        }
                    }
                    System.out.println("[systemDBEngine.getTablesForDatabase] 从文件系统中获取到 " + tables.size() + " 个表");
                }
            }
            
            return tables;
        } catch (Exception e) {
            System.err.println("[systemDBEngine.getTablesForDatabase] 获取表列表出错: " + e.getMessage());
            e.printStackTrace();
            return tables;
        }
    }

}